Fixed GtkCellAreaIter to notify invalidation of sizes on flush
authorTristan Van Berkom <tristan.van.berkom@gmail.com>
Sat, 30 Oct 2010 12:40:22 +0000 (21:40 +0900)
committerTristan Van Berkom <tristan.van.berkom@gmail.com>
Sat, 30 Oct 2010 12:40:22 +0000 (21:40 +0900)
Also fixed GtkCellAreaBox to track the iters it creates and flush
them when the overall layout configuration changes (add/remove/reorder/
spacing changed etc).

gtk/gtkcellareabox.c
gtk/gtkcellareaiter.c

index f1a7cc1ea96713026de6324bb37a2e71258b65ae..80b271e73458f30658951c4a3074b040f3288e72 100644 (file)
@@ -97,7 +97,7 @@ static void      gtk_cell_area_box_layout_reorder                 (GtkCellLayout
                                                                   gint                position);
 
 
-/* CellInfo/CellGroup metadata handling */
+/* CellInfo/CellGroup metadata handling and convenience functions */
 typedef struct {
   GtkCellRenderer *renderer;
 
@@ -109,7 +109,7 @@ typedef struct {
 typedef struct {
   GList *cells;
 
-  guint  id : 16;
+  guint  id     : 16;
   guint  expand : 1;
 } CellGroup;
 
@@ -128,16 +128,20 @@ static GList     *list_consecutive_cells (GtkCellAreaBox  *box);
 static GList     *construct_cell_groups  (GtkCellAreaBox  *box);
 static gint       count_expand_groups    (GtkCellAreaBox  *box);
 static gint       count_expand_cells     (CellGroup       *group);
-
+static void       iter_weak_notify       (GtkCellAreaBox  *box,
+                                         GtkCellAreaIter *dead_iter);
+static void       flush_iters            (GtkCellAreaBox  *box);
 
 struct _GtkCellAreaBoxPrivate
 {
-  GtkOrientation orientation;
+  GtkOrientation  orientation;
+
+  GList          *cells;
+  GList          *groups;
 
-  GList         *cells;
-  GList         *groups;
+  GSList         *iters;
 
-  gint           spacing;
+  gint            spacing;
 };
 
 enum {
@@ -168,6 +172,7 @@ gtk_cell_area_box_init (GtkCellAreaBox *box)
   priv->orientation = GTK_ORIENTATION_HORIZONTAL;
   priv->cells       = NULL;
   priv->groups      = NULL;
+  priv->iters       = NULL;
   priv->spacing     = 0;
 }
 
@@ -214,7 +219,7 @@ gtk_cell_area_box_class_init (GtkCellAreaBoxClass *class)
 
 
 /*************************************************************
- *                CellInfo/CellGroup Basics                  *
+ *    CellInfo/CellGroup basics and convenience functions    *
  *************************************************************/
 static CellInfo *
 cell_info_new  (GtkCellRenderer *renderer, 
@@ -379,6 +384,31 @@ count_expand_cells (CellGroup *group)
   return expand_cells;
 }
 
+static void 
+iter_weak_notify (GtkCellAreaBox  *box,
+                 GtkCellAreaIter *dead_iter)
+{
+  GtkCellAreaBoxPrivate *priv = box->priv;
+
+  priv->iters = g_slist_remove (priv->iters, dead_iter);
+}
+
+static void
+flush_iters (GtkCellAreaBox *box)
+{
+  GtkCellAreaBoxPrivate *priv = box->priv;
+  GSList                *l;
+
+  /* When the box layout changes, iters need to
+   * be flushed and sizes for the box get requested again
+   */
+  for (l = priv->iters; l; l = l->next)
+    {
+      GtkCellAreaIter *iter = l->data;
+
+      gtk_cell_area_iter_flush (iter);
+    }
+}
 
 /*************************************************************
  *                      GObjectClass                         *
@@ -386,6 +416,15 @@ count_expand_cells (CellGroup *group)
 static void
 gtk_cell_area_box_finalize (GObject *object)
 {
+  GtkCellAreaBox        *box = GTK_CELL_AREA_BOX (object);
+  GtkCellAreaBoxPrivate *priv = box->priv;
+  GSList                *l;
+
+  for (l = priv->iters; l; l = l->next)
+    g_object_weak_unref (G_OBJECT (l->data), (GWeakNotify)iter_weak_notify, box);
+
+  g_slist_free (priv->iters);
+
   G_OBJECT_CLASS (gtk_cell_area_box_parent_class)->finalize (object);
 }
 
@@ -463,15 +502,13 @@ gtk_cell_area_box_remove (GtkCellArea        *area,
 
       priv->cells = g_list_delete_link (priv->cells, node);
 
-      /* Reconstruct cell groups
-       * XXX TODO: add a list of iters and weak_ref's on them, then
-       * flush the iters when we reconstruct groups, change spacing
-       * or child expand properties (i.e. notify size needs to be
-       * recalculated).
-       */
+      /* Reconstruct cell groups */
       g_list_foreach (priv->groups, (GFunc)cell_group_free, NULL);
       g_list_free (priv->groups);
       priv->groups = construct_cell_groups (box);
+
+      /* Notify that size needs to be requested again */
+      flush_iters (box);
     }
   else
     g_warning ("Trying to remove a cell renderer that is not present GtkCellAreaBox");
@@ -517,7 +554,16 @@ gtk_cell_area_box_render (GtkCellArea        *area,
 static GtkCellAreaIter *
 gtk_cell_area_box_create_iter (GtkCellArea *area)
 {
-  return (GtkCellAreaIter *)g_object_new (GTK_TYPE_CELL_AREA_BOX_ITER, NULL);
+  GtkCellAreaBox        *box  = GTK_CELL_AREA_BOX (area);
+  GtkCellAreaBoxPrivate *priv = box->priv;
+  GtkCellAreaIter       *iter =
+    (GtkCellAreaIter *)g_object_new (GTK_TYPE_CELL_AREA_BOX_ITER, NULL);
+
+  priv->iters = g_slist_prepend (priv->iters, iter);
+
+  g_object_weak_ref (G_OBJECT (iter), (GWeakNotify)iter_weak_notify, box);
+
+  return iter;
 }
 
 static GtkSizeRequestMode 
@@ -1012,6 +1058,14 @@ gtk_cell_area_box_layout_reorder (GtkCellLayout      *cell_layout,
 
       priv->cells = g_list_delete_link (priv->cells, node);
       priv->cells = g_list_insert (priv->cells, info, position);
+
+      /* Reconstruct cell groups */
+      g_list_foreach (priv->groups, (GFunc)cell_group_free, NULL);
+      g_list_free (priv->groups);
+      priv->groups = construct_cell_groups (box);
+      
+      /* Notify that size needs to be requested again */
+      flush_iters (box);
     }
 }
 
@@ -1049,10 +1103,13 @@ gtk_cell_area_box_pack_start  (GtkCellAreaBox  *box,
 
   priv->cells = g_list_append (priv->cells, info);
 
-  /* Reconstruct cell groups (TODO, notify created iters that size needs renegotiation) */
+  /* Reconstruct cell groups */
   g_list_foreach (priv->groups, (GFunc)cell_group_free, NULL);
   g_list_free (priv->groups);
   priv->groups = construct_cell_groups (box);
+
+  /* Notify that size needs to be requested again */
+  flush_iters (box);
 }
 
 void
@@ -1080,10 +1137,13 @@ gtk_cell_area_box_pack_end (GtkCellAreaBox  *box,
 
   priv->cells = g_list_append (priv->cells, info);
 
-  /* Reconstruct cell groups (TODO, notify created iters that size needs renegotiation) */
+  /* Reconstruct cell groups */
   g_list_foreach (priv->groups, (GFunc)cell_group_free, NULL);
   g_list_free (priv->groups);
   priv->groups = construct_cell_groups (box);
+
+  /* Notify that size needs to be requested again */
+  flush_iters (box);
 }
 
 gint
@@ -1108,7 +1168,9 @@ gtk_cell_area_box_set_spacing (GtkCellAreaBox  *box,
     {
       priv->spacing = spacing;
 
-      /* TODO, notify created iters that size needs renegotiation */
       g_object_notify (G_OBJECT (box), "spacing");
+
+      /* Notify that size needs to be requested again */
+      flush_iters (box);
     }
 }
index 4257f4b754b19ca05984d27d6ab1ccde4b6fd054..4b313648e5936dc5aa8d516df3f80e4e9ad2df15 100644 (file)
@@ -318,6 +318,18 @@ gtk_cell_area_iter_real_flush_preferred_width (GtkCellAreaIter *iter)
   g_object_thaw_notify (G_OBJECT (iter));
 }
 
+static void
+notify_invalid_height (gpointer         width_ptr,
+                      CachedSize      *size,
+                      GtkCellAreaIter *iter)
+{
+  gint width = GPOINTER_TO_INT (width_ptr);
+
+  /* Notify size invalidated */
+  g_signal_emit (iter, cell_area_iter_signals[SIGNAL_HEIGHT_CHANGED], 
+                0, width, -1, -1);
+}
+
 static void
 gtk_cell_area_iter_real_flush_preferred_height_for_width (GtkCellAreaIter *iter,
                                                          gint             width)
@@ -326,11 +338,18 @@ gtk_cell_area_iter_real_flush_preferred_height_for_width (GtkCellAreaIter *iter,
 
   /* Flush all sizes for special -1 value */
   if (width < 0)
-    g_hash_table_remove_all (priv->heights);
+    {
+      g_hash_table_foreach (priv->heights, (GHFunc)notify_invalid_height, iter);
+      g_hash_table_remove_all (priv->heights);
+    }
   else
-    g_hash_table_remove (priv->heights, GINT_TO_POINTER (width));
+    {
+      g_hash_table_remove (priv->heights, GINT_TO_POINTER (width));
 
-  /* XXX Should we bother signalling removed values as "size-changed" signals ? */
+      /* Notify size invalidated */
+      g_signal_emit (iter, cell_area_iter_signals[SIGNAL_HEIGHT_CHANGED], 
+                    0, width, -1, -1);
+    }
 }
 
 static void
@@ -347,6 +366,18 @@ gtk_cell_area_iter_real_flush_preferred_height (GtkCellAreaIter *iter)
   g_object_thaw_notify (G_OBJECT (iter));
 }
 
+static void
+notify_invalid_width (gpointer         height_ptr,
+                     CachedSize      *size,
+                     GtkCellAreaIter *iter)
+{
+  gint height = GPOINTER_TO_INT (height_ptr);
+
+  /* Notify size invalidated */
+  g_signal_emit (iter, cell_area_iter_signals[SIGNAL_WIDTH_CHANGED], 
+                0, height, -1, -1);
+}
+
 static void
 gtk_cell_area_iter_real_flush_preferred_width_for_height (GtkCellAreaIter *iter,
                                                          gint             height)
@@ -355,11 +386,18 @@ gtk_cell_area_iter_real_flush_preferred_width_for_height (GtkCellAreaIter *iter,
 
   /* Flush all sizes for special -1 value */
   if (height < 0)
-    g_hash_table_remove_all (priv->widths);
+    {
+      g_hash_table_foreach (priv->widths, (GHFunc)notify_invalid_width, iter);
+      g_hash_table_remove_all (priv->widths);
+    }
   else
-    g_hash_table_remove (priv->widths, GINT_TO_POINTER (height));
+    {
+      g_hash_table_remove (priv->widths, GINT_TO_POINTER (height));
 
-  /* XXX Should we bother signalling removed values as "size-changed" signals ? */
+      /* Notify size invalidated */
+      g_signal_emit (iter, cell_area_iter_signals[SIGNAL_WIDTH_CHANGED], 
+                    0, height, -1, -1);
+    }
 }
 
 /*************************************************************